﻿
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using System;
using TinyEngine.Core.Entities;
using TinyEngine.Core.Asset;
namespace TinyEngine.Core.Parsers
{
    public static class ParserHelper
    {
        public static string VectorToString(Vector2 vector)
        {
            return string.Format("{0},{1}", vector.X, vector.Y);
        }
        public static string VectorToString(Vector3 vector)
        {
            return string.Format("{0},{1},{2}", vector.X, vector.Y, vector.Z);
        }

        public static string SingleToString(Single number)
        {
            return string.Format("{0}", number);
        }
        
        public static Vector2 TryParseVector(string attributeName, XElement element)
        {
            var att=element.Attribute(attributeName);
            if(att == null)
                return Vector2.Zero;

            var data = att.Value.Split(',');
            return new Vector2(float.Parse(data[0]), float.Parse(data[1]));
        }
        public static Vector3 TryParseVector3(string attributeName, XElement element)
        {
            var att = element.Attribute(attributeName);
            if (att == null)
                return Vector3.Zero;

            var data = att.Value.Split(',');
            if (data.Length == 3)
                return new Vector3(float.Parse(data[0]), float.Parse(data[1]), float.Parse(data[2]));
            else if (data.Length == 2)
                return new Vector3(float.Parse(data[0]), float.Parse(data[1]), 0);
            else if (data.Length == 1)
                return new Vector3(float.Parse(data[0]), float.Parse(data[0]), 0);
            return Vector3.Zero;
        }

        public static string TryParseString(string attributeName, XElement element)
        {
            var att = element.Attribute(attributeName);
            if (att == null)
                return string.Empty;

            return att.Value;
        }

        internal static Point TryParsePoint(string attributeName, XElement element)
        {
            var att = element.Attribute(attributeName);
            if (att == null)
                return Point.Zero;

            var data = att.Value.Split(',');
            return new Point(int.Parse(data[0]), int.Parse(data[1]));
        }

        internal static string PointToString(Point point)
        {
            return string.Format("{0},{1}", point.X, point.Y);
        }

        public static void ParseAssetHolderToXML<T>(IEntity entity, XElement element)
        {
            IAssetHolder<T> assetHolder = entity as IAssetHolder<T>;
            if (assetHolder == null) return;

            element.SetAttributeValue("AssetName", assetHolder.AssetName);
        }

        public static void ParseIEntityToXml(IEntity obj, XElement element)
        {
            element.SetAttributeValue("Name", obj.Name);
            element.SetAttributeValue("Position", ParserHelper.VectorToString(obj.Position));

            var drawable = obj as IRenderable;
            if (drawable != null)
            {
                if (!drawable.Visible) // defaults to true
                    element.SetAttributeValue("Visible", "False");
            }
        }

        internal static float TryParseFloat(string name, XElement item, float defaultValue)
        {
            var att = item.Attribute(name);
            if (att == null)
                return defaultValue;

            return float.Parse(item.Value);
        }

        public static Rectangle TryParseRectangle(string name, XElement element)
        {
            var att = element.Attribute(name);
            if (att == null)
                return Rectangle.Empty;

            var data = att.Value.Split(',');
            return new Rectangle(int.Parse(data[0]), int.Parse(data[1]), int.Parse(data[2]), int.Parse(data[3]));
        }

        public static void ParseStringToXml(XElement element, string val, string name)
        {
            if (string.IsNullOrEmpty(val))
                return;

            element.SetAttributeValue(name, val);
        }

        public static string RectangleToString(Rectangle rectangle)
        {
            var val = rectangle.X + "," +
                        rectangle.Y + "," +
                        rectangle.Width + "," +
                        rectangle.Height;
            return val;
        }

        public static double TryParseDouble(string name, XElement element)
        {
            double val = 0;
            var attrib = element.Attribute(name);
            if(attrib == null)
                return val;
            
            if (!double.TryParse(attrib.Value, out val))
                val = 0;

            return val;
        }

        public static Single TryParseSingle(string name, XElement element)
        {
            Single val = 0;
            var attrib = element.Attribute(name);
            if (attrib == null)
                return val;

            if (!Single.TryParse(attrib.Value, out val))
                val = 0;

            return val;
        }

        public static bool TryParseBool(string name, XElement item)
        {
            return TryParseBool(name, item, false);
        }

        public static bool TryParseBool(string name, XElement item, bool defaultVal)
        {
            bool val = defaultVal;
            var attrib = item.Attribute(name);
            if (attrib == null)
                return val;

            if (!bool.TryParse(attrib.Value, out val))
                val = defaultVal;

            return val;
        }

        public static void ParseXmlToIEntity(XElement element, IEntity entity)
        {

            entity.Name = element.Attribute("Name").Value;
            entity.Position = ParserHelper.TryParseVector3("Position", element);

            var renderable = entity as IRenderable;
            if (renderable != null)
            {
                renderable.Visible = ParserHelper.TryParseBool("Visible", element, true);
            }
            
            var spriteHolder = entity as IAssetHolder<SpriteAsset>;
            if (spriteHolder != null)
            {
                string assetName = ParserHelper.TryParseString("AssetName", element);
                if (!string.IsNullOrEmpty(assetName))
                {
                    spriteHolder.AssetName = assetName;
                }
            }

        }
    }

    public static class XMLParserHelper
    {
        public static object ParseFromXML<T>(string elementName, XElement element)
        {
            var attribute = element.Attribute(elementName);
            if(attribute == null)
                return default(T);

            var val = attribute.Value;
            if (string.IsNullOrEmpty(val))
                return default(T);

            if (typeof(T) == typeof(string))
            {
                return val;
            }
            else if (typeof(T) == typeof(int))
            {
                return StringToInt(val);
            }
            else if (typeof(T) == typeof(float))
            {
                return StringToFloat(val);
            }
            else if (typeof(T) == typeof(Point))
            {
                return StringToFloat(val);
            }

            return default(T);
        }

        private static Point StringToPoint(string str)
        {
            Point val = new Point();
            var split = str.Split(',');
            if (split.Length == 2)
            {
                val.X = StringToInt(split[0]);
                val.Y = StringToInt(split[1]);
            }
            return val;
        }

        private static Vector2 StringToVector2(string str)
        {
            Vector2 val = new Vector2();
            var split = str.Split(',');
            if (split.Length == 2)
            {
                val.X = StringToFloat(split[0]);
                val.Y = StringToFloat(split[1]);
            }
            else if (split.Length == 1)
            {
                val.X = StringToFloat(split[0]);
                val.Y = StringToFloat(split[0]);
            }
            return val;
        }

        private static Vector3 StringToVector3(string str)
        {
            Vector3 val = new Vector3();
            var split = str.Split(',');
            if (split.Length == 3)
            {
                val.X = StringToFloat(split[0]);
                val.Y = StringToFloat(split[1]);
                val.Z = StringToFloat(split[2]);
            }
            if (split.Length == 2)
            {
                val.X = StringToFloat(split[0]);
                val.Y = StringToFloat(split[1]);
            }
            else if (split.Length == 1)
            {
                val.X = StringToFloat(split[0]);
                val.Y = StringToFloat(split[0]);
            }
            return val;
        }
        
        private static float StringToFloat(string str)
        {
            float val = 0;
            if (!float.TryParse(str, out val))
            {
                val = 0;
            }
            return val;
        }


        private static double StringToDouble(string str)
        {
            double val = 0;
            if (!double.TryParse(str, out val))
            {
                val = 0;
            }
            return val;
        }

        private static int StringToInt(string str)
        {
            int val = 0;
            if (!int.TryParse(str, out val))
            {
                val = 0;
            }
            return val;
        }
    }
}
